home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / windownt / lpr10.zip / LPR.C < prev    next >
C/C++ Source or Header  |  1992-11-08  |  15KB  |  640 lines

  1. /*
  2.  * lpr.c - Windows NT lpr
  3.  *
  4.  * by Eric W. Brown
  5.  *    28 October '92
  6.  */
  7.  
  8. #include <windows.h>
  9. #include <winbase.h>
  10. #include <winsock.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <stdio.h>
  14. #include <fcntl.h>
  15. #include <sys/types.h>
  16. #include <sys/stat.h>
  17. #include <sys/locking.h>
  18. #include <io.h>
  19.  
  20. #include "lp.h"
  21.  
  22. /*
  23.  * #defines
  24.  */
  25. #define HOSTNAME_LEN    (MAX_COMPUTERNAME_LENGTH + 1)
  26. #define USERNAME_LEN    (32 /* MAX_USERNAME_LENGTH */ + 1)
  27.  
  28.  
  29. /*
  30.  * Global Variables
  31.  */
  32. int        sockfd = -1;
  33. char    hostname[HOSTNAME_LEN];
  34. char    username[USERNAME_LEN];
  35. char    *printer = NULL;
  36. char    *server = NULL;
  37. char    *temp_dir = NULL;
  38. char    *class = NULL;
  39. char    *job = NULL;
  40. char    *title = NULL;
  41. char    filter = 'f';
  42. int        noburst = 0;
  43. int        debug = 0;
  44. int        dosfilter = 0;
  45. int        width = 0;
  46. int        copies = 1;
  47. int        indent = -1;
  48. int        tcp_initialized = 0;
  49. int        seqno;
  50. FILE    *cf_file = NULL;
  51. char    tmp_cfname[33] = "";
  52. char    tmp_dfname[33] = "";
  53. char    tmp_stdin_fname[33] = "";
  54.  
  55.  
  56. /*
  57.  * Prototypes
  58.  */
  59. int usage();
  60. void lpr_start_protocol();
  61. void lpr_finish_protocol();
  62. void lpr_print_file(char *filename, char *name);
  63. void lpr_send_file(int fd, int length);
  64. void lpr_send(char *buf, int cnt);
  65. void lpr_check_ack();
  66. void lpr_create_control_file(char *tmp_cfname);
  67. void lpr_capture_stdin(char *fname);
  68. long lpr_text_filelength(int fd);
  69. void lpr_filter_dos(char *infname, char *outfname);
  70. int  lpr_get_seqno(char *seq_fname);
  71. void lpr_crash(int report, char *fmt, ...);
  72. #define NO_REPORT        0
  73. #define REPORT_SOCKERR    1
  74. #define REPORT_FILEERR    2
  75. #define REPORT_ERR        3
  76.  
  77. int usage()
  78. {
  79.     fprintf(stderr, "Usage: lpr [ -Pprinter ] [ -Sserver ] [ -#num ] [ -C class ] [ -J job ]\n");
  80.     fprintf(stderr, "           [ -T title ] [ -i [ numcols ]] [ -wnum ] [ -pvcgdntlfhD ]\n");
  81.     fprintf(stderr, "           [ -u ] [ -#n ] [ name ... ]\n");
  82.     fprintf(stderr, "       -u : filter for unix (remove ^M and ^D characters)\n");
  83.     exit(1);
  84.     return 0;
  85. } /* usage() */
  86.  
  87. void main(int argc, char **argv)
  88. {
  89.     char    *ptr;
  90.     long    fileHandle;
  91.     struct _finddata_t fileinfo;
  92.     int        length;
  93.     char    filename[256];
  94.     
  95.     /*
  96.      * Get environment variables:
  97.      *   server, printer, hostname, username & temp_dir
  98.      */
  99.     server = getenv("SERVER");
  100.     printer = getenv("PRINTER");
  101.     if (!printer)
  102.         printer = DEFAULT_PRINTER;
  103.     
  104.     length = HOSTNAME_LEN;
  105.     if (!GetComputerName(hostname, &length) || length == 0)
  106.         lpr_crash(REPORT_ERR, "lpr: No hostname, name your computer!!!\n");
  107.     
  108.     length = USERNAME_LEN;
  109.     if (!GetUserName(username, &length))
  110.         strncpy(username, hostname, USERNAME_LEN);
  111.     
  112.     temp_dir = getenv("TEMP");
  113.     if (!temp_dir) {
  114.         fprintf(stderr, "lpr: TEMP environment variable not set.\n");
  115.         exit(1);
  116.     }
  117.     else if (_access(temp_dir, 06) < 0) {
  118.         fprintf(stderr, "lpr: TEMP directory, %s, does not exist or %s\n", 
  119.                 temp_dir, "invalid permissions");
  120.         exit(1);
  121.     } /* else */
  122.     
  123.     
  124.     /*
  125.      * Parse command line
  126.      */
  127. #define NEXT_ARG()  (argc--, argv++, argc ? *argv : (char *)(usage(), NULL))
  128. #define ARG_ARG()   (strlen(*argv) == 2 ? NEXT_ARG() : (*argv) + 2)
  129.     while (argc > 1 && argv[1][0] == '-') {
  130.         NEXT_ARG();
  131.         switch(argv[0][1]) {
  132.         case 'P':    printer = ARG_ARG();        break;
  133.         case 'S':    server = ARG_ARG();            break;
  134.         case 'C':    class = ARG_ARG();            break;
  135.         case 'J':    job = ARG_ARG();            break;
  136.         case 'T':    title = ARG_ARG();            break;
  137.         case 'p':
  138.         case 'v':
  139.         case 'c':
  140.         case 'g':
  141.         case 'd':
  142.         case 'n':
  143.         case 't':
  144.         case 'l':    filter = argv[0][1];        break;
  145.         case 'f':    filter = 'r';                break;
  146.         case 'h':    noburst = 1;                break;
  147.         case 'D':    debug = 1;                    break;
  148.         case 'u':    dosfilter = 1;                break;
  149.         
  150.         case 'i':
  151.             indent = (*argv[2] ? atoi(*argv + 2) : 8);
  152.             if (indent < 0 || indent > 255) {
  153.                 fprintf(stderr, "lpr: %s: invalid indentation, %s",
  154.                         *argv, "please keep it between 0 and 255.\n");
  155.                 usage();
  156.             } /* if */
  157.             break;
  158.             
  159.         case 'w':
  160.             if (sscanf(ARG_ARG(), "%d", &width) != 1) {
  161.                 fprintf(stderr, "lpr: invalid width\n");
  162.                 usage();
  163.             } /* if */
  164.             break;    
  165.             
  166.         case '#':
  167.             if (sscanf(ARG_ARG(), "%d", &copies) != 1) {
  168.                 fprintf(stderr, "lpr: # of copies must be an integer.\n");
  169.                 exit(1);
  170.             } /* if */
  171.             break;
  172.             
  173.         default:
  174.             fprintf(stderr, "lpr: '%s' invalid option\n", *argv);
  175.             usage();
  176.         } /* switch */
  177.     } /* while argc */
  178.  
  179.  
  180.     /*
  181.      * Loop over remaining arguments, (Print these files ...)
  182.      */
  183.     while (argc > 1) {
  184.         NEXT_ARG();
  185.         
  186.         /* For unix compatibility, replace '/'s with '\'s */
  187.         ptr = *argv;
  188.         while(*ptr)
  189.             if (*ptr++ == '/')
  190.                 ptr[-1] = '\\';
  191.                 
  192.         
  193.         if ((fileHandle = _findfirst(*argv, &fileinfo)) != -1L) {
  194.             do {
  195.                 if (!tcp_initialized)
  196.                     lpr_start_protocol();
  197.                 strcpy(filename, *argv);
  198.                 if (ptr = strrchr(filename, '\\'))
  199.                     ptr[1] = '\0';
  200.                 else if (ptr = strrchr(filename, ':'))
  201.                     ptr[1] = '\0';
  202.                 else
  203.                     filename[0] = '\0';
  204.                 strcat(filename, fileinfo.name);
  205.                 lpr_print_file(filename, filename);
  206.             } while (_findnext(fileHandle, &fileinfo) == 0);
  207.             _findclose(fileHandle);
  208.         }
  209.         else {
  210.             fprintf(stderr, "lpr: %s: Invalid file spec.\n", *argv);
  211.             if (tcp_initialized)
  212.                 break;
  213.             else
  214.                 exit(1);
  215.         } /* else */
  216.     } /* while argc */
  217.     
  218.  
  219.     /*
  220.      * See if we should take input from stdin
  221.      */
  222.     if (!tcp_initialized) {
  223.         lpr_start_protocol();
  224.         sprintf(tmp_stdin_fname, "%s\\sin%03d.tmp", temp_dir, seqno);
  225.         lpr_capture_stdin(tmp_stdin_fname);
  226.         lpr_print_file(tmp_stdin_fname, "(standard input)");
  227.         unlink(tmp_stdin_fname);
  228.     } /* if */
  229.     
  230.  
  231.     /*
  232.      * Clean up
  233.      */
  234.     if (tcp_initialized) {
  235.         lpr_finish_protocol();
  236.         closesocket(sockfd);
  237.         lp_tcp_shutdown();
  238.         fclose(cf_file);
  239.         unlink(tmp_cfname);
  240.     } /* if */
  241.     
  242.     exit(0);
  243. } /* main() */
  244.  
  245.  
  246. void lpr_start_protocol()
  247. {
  248.     char seq_fname[33];
  249.     char message[80];
  250.     
  251.     /*
  252.      * Do a lookup in the printcap file if necessary
  253.      */
  254.     if (!server)
  255.         if (!(server = lp_printcap_server_lookup(printer))) {
  256.             fprintf(stderr, "lpr: No server, %s, and no printer, %s, %s",
  257.                     server, printer, "in printcap file!\n");
  258.             usage();
  259.         } /* if */
  260.     
  261.     
  262.     /*
  263.      * Initialize tcp
  264.      */
  265.     if (lp_tcp_startup())
  266.         lpr_crash(REPORT_SOCKERR, "lpr: Couldn't initialize tcp/ip\n");
  267.     tcp_initialized = 1;
  268.     if (debug) fprintf(stderr, "lpr: Initialized TCP/IP\n");
  269.     
  270.     
  271.     /*
  272.      * Open a socket
  273.      */
  274.     if ((sockfd = lp_tcp_open(server)) < 0)
  275.         lpr_crash(REPORT_SOCKERR, "lpr: Couldn't open connection to server, %s\n",
  276.                   server);
  277.     if (debug) fprintf(stderr, "lpr: Connected to server, %s\n", server);
  278.     
  279.  
  280.     /*
  281.      * Get sequence number and increment it
  282.      */
  283.     sprintf(seq_fname, "%s\\lpr.seq", temp_dir);
  284.     seqno = lpr_get_seqno(seq_fname);
  285.     
  286.     
  287.     /*
  288.      * Create control file
  289.      */
  290.     sprintf(tmp_cfname, "%s\\cfA%03d.tmp", temp_dir, seqno);
  291.     lpr_create_control_file(tmp_cfname);
  292.     
  293.     
  294.     /*
  295.      * Tell LPD to receive a job
  296.      */
  297.     sprintf(message, "%c%s\n", LPD_PRINT_JOB, printer);
  298.     lpr_send(message, strlen(message));
  299.     lpr_check_ack();
  300.     if (debug) fprintf(stderr, "lpr: Server is accepting job.\n");
  301. } /* lpr_start_protocol() */
  302.  
  303.  
  304. void lpr_finish_protocol()
  305. {
  306.     int length;
  307.     char message[80];
  308.     
  309.     /*
  310.      * Send control file receive message
  311.      */
  312.     fflush(cf_file);
  313.     length = _filelength(_fileno(cf_file));
  314.     sprintf(message, "%c%d cfA%03d%s\n", LPD_RECEIVE_CONTROL_FILE,
  315.             length, seqno, hostname);
  316.     lpr_send(message, strlen(message));
  317.     lpr_check_ack();
  318.     
  319.     /*
  320.      * Send control file
  321.      */
  322.     if (debug) fprintf(stderr, "lpr: Sending control file to %s\n", server);
  323.     _lseek(_fileno(cf_file), 0, SEEK_SET);
  324.     lpr_send_file(_fileno(cf_file), length);
  325. } /* lpr_finish_protocol() */
  326.     
  327.     
  328. void lpr_print_file(char *filename, char *name)
  329. {
  330.     static int    file_count = 0;
  331.     static char    *df_prefix = "df?";
  332.     char    dfname[65];
  333.     int        fd;
  334.     int        length;
  335.     char    message[80];
  336.     int        i;
  337.     int        is_text;
  338.     
  339.     /*
  340.      * Create df filename
  341.      */
  342.     if (file_count++ % 26 == 0)
  343.         df_prefix[2]++;
  344.     else if (file_count == 27)
  345.         df_prefix = "dfA@";
  346.     df_prefix[strlen(df_prefix) - 1]++;
  347.     sprintf(dfname, "%s%03d%s", df_prefix, seqno, hostname);
  348.     
  349.     
  350.     /*
  351.      * See if we need to make a temporary file
  352.      */
  353.     if (dosfilter) {
  354.         sprintf(tmp_dfname, "%s\\%s%03d.tmp", temp_dir, df_prefix, seqno);
  355.         lpr_filter_dos(filename, tmp_dfname);
  356.     } /* if */
  357.     
  358.     
  359.     /*
  360.      * Add to control file
  361.      */
  362.     if (width) fprintf(cf_file, "W%d\n", width);
  363.     if (indent != -1) fprintf(cf_file, "I%d\n", indent);
  364.     if (filter == 'p') fprintf(cf_file, "T%s\n", (title ? title : name));
  365.     for(i = 0; i < copies; i++)
  366.         fprintf(cf_file, "%c%s\n", filter, dfname);
  367.     fprintf(cf_file, "U%s\n", dfname);
  368.     fprintf(cf_file, "N%s\n", name);
  369.     
  370.     
  371.     /*
  372.      * Open the file
  373.      */
  374.     is_text = (filter == 'f' || filter == 'p' || filter == 'r' || dosfilter);
  375.     fd = open(dosfilter ? tmp_dfname : filename, 
  376.               O_RDONLY | (is_text ? O_TEXT : O_BINARY));
  377.     if (fd < 0)
  378.         lpr_crash(REPORT_FILEERR, "lpr: Couldn't open file, %s\n", filename);
  379.     
  380.     
  381.     /*
  382.      * Try to send a file
  383.      */
  384.     length = (is_text ? lpr_text_filelength(fd) : filelength(fd));
  385.     sprintf(message, "%c%ld %s\n", LPD_RECEIVE_DATA_FILE, length, dfname);
  386.     lpr_send(message, strlen(message));
  387.     lpr_check_ack();
  388.     
  389.     
  390.     /*
  391.      * Send the actual file
  392.      */
  393.     if (debug) fprintf(stderr, "lpr: Sending %s to %s@%s.\n", name, printer, server);
  394.     lpr_send_file(fd, length);
  395.     close(fd);
  396.     if (*tmp_dfname) {
  397.         unlink(tmp_dfname);
  398.         *tmp_dfname = 0;
  399.     } /* if */
  400. } /* lpr_print_file() */
  401.  
  402.  
  403. void lpr_send_file(int fd, int length)
  404. {
  405.     int cnt;
  406.     char buf[1024];
  407.     
  408.     /* 
  409.      * Send the file
  410.      */
  411.     while(length) {
  412.         cnt = min(length, 1024);
  413.         if ((cnt = read(fd, buf, cnt)) <= 0)
  414.             lpr_crash(REPORT_FILEERR, "lpr: Error reading file\n");
  415.         
  416.         lpr_send(buf, cnt);
  417.         length -= cnt;
  418.     } /* while */
  419.     
  420.     
  421.     /*
  422.      * Send end mark & get acknowledgement
  423.      */
  424.     sprintf(buf, "%c", LPD_END_TRANSFER);
  425.     lpr_send(buf, 1);
  426.     lpr_check_ack();
  427. } /* lpr_send_file() */
  428.  
  429.  
  430. void lpr_send(char *buf, int cnt)
  431. {
  432.     if (send(sockfd, buf, cnt, 0) != cnt)
  433.         lpr_crash(REPORT_SOCKERR, "lpr: Error talking to server, %s\n", server);
  434. } /* lpr_send() */
  435.  
  436.  
  437. void lpr_check_ack()
  438. {
  439.     char    buf[80];
  440.     int        len;
  441.     
  442.     while(1) {
  443.         len = recv(sockfd, buf, 79, 0);
  444.         if (len <= 0)
  445.             lpr_crash(REPORT_SOCKERR, "lpr: Server not responding.\n");
  446.         switch(buf[0]) {
  447.         case LPD_OK:
  448.             return;
  449.         case LPD_ERROR:
  450.             lpr_crash(NO_REPORT, "lpr: Server error\n");
  451.         case LPD_NO_SPOOL_SPACE:
  452.             lpr_crash(NO_REPORT, "lpr: Unable to accept job at this time.\n%s",
  453.                                  "Not enough spool space on server.\n");
  454.         default:
  455.             /* An error message? */
  456.             buf[len] = 0;
  457.             fprintf(stderr, "%s", buf);
  458.         } /* switch */
  459.     } /* while */
  460. } /* check_ack() */
  461.  
  462.  
  463. void lpr_create_control_file(char *tmp_cfname)
  464. {
  465.     /*
  466.      * Open the control file
  467.      */
  468.     cf_file = fopen(tmp_cfname, "w+b");
  469.     if (!cf_file)
  470.         lpr_crash(REPORT_FILEERR, "lpr: Couldn't open file, %s\n", tmp_cfname);
  471.     
  472.     
  473.     /*
  474.      * Start building the control file
  475.      */
  476.     fprintf(cf_file, "H%s\n", hostname);
  477.     fprintf(cf_file, "P%s\n", username);
  478.     if (!noburst) {
  479.         if (job)
  480.             fprintf(cf_file, "J%s\n", job);
  481.         fprintf(cf_file, "C%s\n", class ? class : hostname);
  482.         fprintf(cf_file, "L%s\n", username);
  483.     } /* if */
  484. } /* lpr_create_control_file() */
  485.  
  486.  
  487. void lpr_capture_stdin(char *fname)
  488. {
  489.     char buf[1024];
  490.     int  len;
  491.     int  fd;
  492.     
  493.     if (debug) fprintf(stderr, "lpr: Capturing stdin to '%s'\n", fname);
  494.     
  495.     fd = open(fname, _O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY, 0666);
  496.     if (fd < 0)
  497.         lpr_crash(NO_REPORT, "lpr: Error creating temporary file, %s\n", fname);
  498.     
  499.     while((len = read(0, buf, 1024)) > 0)
  500.         if (_write(fd, buf, len) != len)
  501.             lpr_crash(NO_REPORT, "lpr: Error writing to tmp file, %s\n", fname);
  502.  
  503.     close(fd);
  504.     
  505. } /* lpr_capture_stdin() */
  506.  
  507.  
  508. int lpr_get_seqno(char *seq_fname)
  509. {
  510.     int seqno;
  511.     int fd;
  512.     int    cnt;
  513.     char buf[80];
  514.     
  515.     /*
  516.      * Open the sequence file, if it doesn't exist, create it.
  517.      */
  518.     if ((fd = _open(seq_fname, _O_RDWR | _O_CREAT | _O_TEXT)) < 0)
  519.         lpr_crash(REPORT_FILEERR, "lpr: Couldn't open (or create) sequence file (%s)\n",
  520.                   seq_fname);
  521.     
  522.     
  523.     /*
  524.      * Lock the file (the first byte of it anyway)
  525.      */
  526.     if (_locking(fd, _LK_LOCK, 1))
  527.         lpr_crash(REPORT_FILEERR, "lpr: Couldn't lock sequence file, %s\n", seq_fname);
  528.  
  529.  
  530.     /*
  531.      * Get the sequence number
  532.      */
  533.     cnt = read(fd, buf, 79);
  534.     buf[cnt] = 0;
  535.     if (sscanf(buf, "%d", &seqno) != 1)
  536.         seqno = 1;
  537.     
  538.     
  539.     /*
  540.      * Write new sequence number
  541.      */
  542.     _lseek(fd, 0, SEEK_SET);
  543.     sprintf(buf, "%03d\n", (seqno + 1) % 1000);
  544.     write(fd, buf, strlen(buf));
  545.  
  546.     
  547.     /*
  548.      * Unlock & close file
  549.      */
  550.     _lseek(fd, 0, SEEK_SET);
  551.     _locking(fd, _LK_UNLCK, 1);    
  552.     _close(fd);
  553.     
  554.     return (seqno);
  555. } /* lpr_get_seqno() */
  556.  
  557.  
  558. void lpr_crash(int report, char *fmt, ...)
  559. {
  560.     va_list    marker;
  561.     
  562.     if (fmt) {
  563.         va_start(marker, fmt);
  564.         vfprintf(stderr, fmt, marker);
  565.         va_end(marker);
  566.     } /* if */
  567.     
  568.     if (tcp_initialized) {
  569.         if (sockfd != -1)    closesocket(sockfd);
  570.                             lp_tcp_shutdown();
  571.         if (cf_file)        fclose(cf_file);
  572.         if (*tmp_dfname)    unlink(tmp_dfname);
  573.         if (*tmp_stdin_fname) unlink(tmp_stdin_fname);
  574.     } /* if */
  575.     
  576.     exit(1);
  577. } /* lpr_crash() */
  578.  
  579.  
  580. long lpr_text_filelength(int fd)
  581. {
  582.     char    buf[1024];
  583.     int        length = 0;
  584.     int        cnt;
  585.     
  586.     /* Read the whole file */
  587.     while((cnt = read(fd, buf, 1024)) > 0)
  588.         length += cnt;
  589.     
  590.     /* Rewind to the beginning */
  591.     lseek(fd, 0, SEEK_SET);
  592.  
  593.     return length;
  594. } /* lpr_text_filelength() */
  595.  
  596.  
  597. void lpr_filter_dos(char *infname, char *outfname)
  598. {
  599.     FILE    *in_file;
  600.     FILE    *out_file;
  601.     char    buf[1024];
  602.     char    *ptr;
  603.     
  604.     if (debug) fprintf(stderr, "lpr: Filtering ^D's from '%s' to '%s'\n",
  605.                        infname, outfname);
  606.     
  607.     in_file = fopen(infname, "rt");
  608.     if (!in_file)
  609.         lpr_crash(REPORT_FILEERR, "lpr: Couldn't open file '%s'\n", infname);
  610.     
  611.     out_file = fopen(outfname, "wt");
  612.     if (!out_file)
  613.         lpr_crash(REPORT_FILEERR, "lpr: Couldn't create file '%s'\n", outfname);
  614.     
  615.     while(!feof(in_file)) {
  616.         /* Try to get one line of text */
  617.         fgets(ptr = buf, 1023, in_file);
  618.  
  619.         /* Exclude lines that begin with ^D or ^Z */
  620.         if (buf[0] == 4 || buf[0] == 26)
  621.             if (*++ptr == '\n')
  622.                 continue;
  623.         
  624.         while(ptr[0] && !feof(in_file)) {
  625.             if (fputs(ptr, out_file) == EOF)
  626.                 lpr_crash(REPORT_FILEERR, "lpr: Couldn't write to file '%s'\n", 
  627.                           outfname);
  628.                           
  629.             if (ptr[strlen(ptr) - 1] == '\n')
  630.                 break;
  631.             
  632.             fgets(ptr = buf, 1023, in_file);
  633.         } /* while */
  634.     } /* while */
  635.     
  636.     fclose(in_file);
  637.     fclose(out_file);
  638. } /* lpr_filter_dos() */
  639.  
  640.